/**********************************************************************************************************************
 * @file    pair.c
 * @author  Queclink Jason.Huang
 * @date    2022-04-26
 * @brief   PAIR Messages (Quectel)
 *
 * Copyright (C) 2022 Queclink Wireless Solutions (ShenZhen) Co., Ltd. All Rights Reserved.
 *
 * @attention
 *
 * @usage
 *
 *********************************************************************************************************************/
#include "aadl/aadl.h"
#include <stdbool.h>
#include "pair.h"
#include <qlcommon.h>
#include <gnss_public.h>
#include <gnss_command.h>
#include "gnss_log.h"
#include "bsp_gnss.h"

enum {
    ACK_RES_SENT_SUCCESS= 0,        /* 指令已成功发送 */
    ACK_RES_PROCESSED   = 1,        /* 正在处理 */
    ACK_RES_SENT_FAIL   = 2,        /* 指令发送失败 */
    ACK_RES_NOT_SUPPORT = 3,        /* 指令不支持 */
    ACK_RES_PARAM_ERROR = 4,        /* 指令参数错误 */
    ACK_RES_MNL_BUSY    = 5,        /* 处理繁忙 */
};

extern unsigned char pqcmd_checksum_cal(char* msg);

#define PAIR_CMD_MAX_LEN    128
int pairCommandSend(pairCmd_t cmd, void *param)
{
    char *cmdStr = NULL;
    unsigned char chksum = 0;
    int cmdLen = 0;
    int ret = -1;
    const char ch[4] = {0xFF, 0xFF, 0xFF, 0xFF};

    cmdStr = qlmalloc(PAIR_CMD_MAX_LEN);
    if (NULL == cmdStr)
        return -ENOMEM;

    switch (cmd) {
    case PAIR_SET_GNSS_SEARCH:
        sprintf(cmdStr, PAIR_HEAD_STR "%03d,%d,%d,%d,%d,%d,0*", cmd,
                                !!(((unsigned int)(param))&GNSS_GPS),
                                !!(((unsigned int)(param))&GNSS_GLONASS),
                                !!(((unsigned int)(param))&GNSS_GALILEO),
                                !!(((unsigned int)(param))&GNSS_BEIDOU),
                                !!(((unsigned int)(param))&GNSS_GPS));
        break;

    case PAIR_IO_SET_BAUDRATE:
        sprintf(cmdStr, PAIR_HEAD_STR "%03d,0,0,%d*", cmd,
                                ((unsigned int)(param)));
        break;

    case PAIR_ENTER_RTC_MODE:
        sprintf(cmdStr, PAIR_HEAD_STR "%03d,0*", cmd);
        break;

    case PAIR_REF_LOC:
        sprintf(cmdStr, PAIR_HEAD_STR "%03d,%9.6f,%10.6f,%.1f,50.0,50.0,0,100.0*", cmd,\
                                      ((struct pairRefLoc*)(param))->lat,\
                                      ((struct pairRefLoc*)(param))->lon,\
                                      ((struct pairRefLoc*)(param))->height);
        break;

    case PAIR_REF_UTC:
        sprintf(cmdStr, PAIR_HEAD_STR "%03d,%d,%d,%d,%d,%d,%d*",cmd,\
                                      ((struct pairRefUtc*)(param))->year,\
                                      ((struct pairRefUtc*)(param))->month,\
                                      ((struct pairRefUtc*)(param))->day,\
                                      ((struct pairRefUtc*)(param))->hour,\
                                      ((struct pairRefUtc*)(param))->minute,\
                                      ((struct pairRefUtc*)(param))->second);
        break;

    case PAIR_GET_EPO_STATUS:
        sprintf(cmdStr, PAIR_HEAD_STR "%03d,0*", cmd);
        break;

    case PAIR_CMD_ACTIVATE:
        sprintf(cmdStr, PAIR_HEAD_STR "%d,%s*", cmd, (char*)param);
        break;

    case PAIR_IO_SET_FLOW_CONTROL:
        sprintf(cmdStr, "$PAIR%03d,0,0,0*",cmd);
        break;

    case PAIR_IO_GET_BAUDRATE:
        sprintf(cmdStr, "$PAIR%03d,0,0*",cmd);
        break;

    case PAIR_NVRAM_AUTO_SAVING_ENABLE:
        sprintf(cmdStr, "$PAIR%03d,%d*", cmd, (int)((void *)param));
        break;

    default:        /* 默认是没有参数的指令 */
        sprintf(cmdStr, PAIR_HEAD_STR "%03d*", cmd);
        break;
    }

    chksum = pqcmd_checksum_cal(cmdStr);
    sprintf(cmdStr+strlen(cmdStr),"%02X\r\n", chksum);

    cmdLen = strlen(cmdStr);

    /* 串口唤醒响应10ms~20ms */
    bsp_gnss_write(ch, 4);         /* 发送指令之前，先通过UART唤醒 */
    vTaskDelay(_MS2TICKS(20));
    bsp_gnss_write(ch, 4);         /* 发送指令之前，先通过UART唤醒 */
    vTaskDelay(_MS2TICKS(10));
    bsp_gnss_write(ch, 4);         /* 发送指令之前，先通过UART唤醒 */
    vTaskDelay(_MS2TICKS(10));
    ret = bsp_gnss_write(cmdStr, cmdLen);
    ret = (cmdLen != ret)? -EIO:0;

    gnss_trace(LOG_DEBUG "==> %s\r\n", cmdStr);

    qlfree(cmdStr);
    return ret;
}

__weak unsigned char pqcmd_checksum_cal(char* msg)
{
    unsigned char chksum = 0;
    msg++;
    while(*msg != '*') {chksum ^= *msg++;}
    return chksum;
}
